import axios, { Axios, AxiosError } from "axios";
import os from "os";
import fs from "fs-extra";
import moment from "moment";
import path from "path";
import { toolchain } from "../toolchain.js";
import { Hudson } from "./hudson.js";
import _ from "lodash";
import { env } from "../env.js";
import { TVersionInfo } from "../Ancestor.js";

export const MsgSupporter = 'douyin';

export const enum EFileErrorType {
    CodeError = 1,
    FileNameError
}

const __fileErrorDescMap = {
    [EFileErrorType.CodeError]: '代码有误，请马上处理！',
    [EFileErrorType.FileNameError]: '文件命名错误，请马上处理！'
}

const __alertVar = { userAlreadyAlert: '' };

let _defaultChatId: string;
export async function setDefaultChatId(chatId: string) {
    _defaultChatId = chatId;
}

function getChatId(): string {
    return toolchain.params.channelCfg?.chatid ?? _defaultChatId;
}

export async function alertErrorFile(file: string, type: EFileErrorType, msg?: string): Promise<string> {
    if (!path.isAbsolute(file)) {
        if (file.endsWith('.ts') && !file.startsWith('TsScripts')) file = path.join('TsScripts', file);
        file = path.join(toolchain.params.workSpacePath, file);
    }    
    const info = await toolchain.svnClient.info([file], { showItem: 'last-changed-author' });
    const touser = info.trim();
    let s = __fileErrorDescMap[type] + '\n' + `项目：${toolchain.option.projectName}`;
    if (msg) {
        s += `\n错误信息: ${msg}`;
    }
    await sendUserChat('text', touser, s);
    return touser;
}

async function makeBuildReport(success: boolean, versionInfo: TVersionInfo | null, content: string, appendLogURL: boolean): Promise<feishu.ICardMessagePayload> {
    const now = _.now();
    const timeslapse = now - toolchain.startAt;
    const timeStr = moment(timeslapse).utcOffset(0).format('HH:mm:ss');
    const elements: feishu.IMsgElement[] = [
        {
            "tag": "markdown",
            "content": `${Hudson.getJobName()} #${Hudson.getBuildNumber()} (${Hudson.getBuildID()})`,
            "text_align": "left",
            "text_size": "normal",
            "icon": {
                "tag": "standard_icon",
                "token": "search-outline_outlined",
                "color": "red"
            }
        },
        {
            "tag": "markdown",
            "content": `时间: ${moment().format(moment.HTML5_FMT.TIME)}`,
            "text_align": "left",
            "text_size": "normal",
            "icon": {
                "tag": "standard_icon",
                "token": "time_outlined",
                "color": "grey"
            }
        },
        {
            "tag": "markdown",
            "content": `耗时: ${timeStr}`,
            "text_align": "left",
            "text_size": "normal",
            "icon": {
                "tag": "standard_icon",
                "token": "alarm-clock_filled",
                "color": "green"
            }
        }
    ];
    if (versionInfo) {
        elements.push({
            "tag": "markdown",
            "content": `版本号: ${versionInfo.version}`,
            "text_align": "left",
            "text_size": "normal",
            "icon": {
                "tag": "standard_icon",
                "token": "link-copy_outlined",
                "color": "blue"
            }
        });
    }
    if (content) {
        elements.push({
            "tag": "markdown",
            content,
            "text_align": "left",
            "text_size": "normal",
            "icon": {
                "tag": "standard_icon",
                "token": "warning_filled",
                "color": "red"
            }
        });
    }

    const link = `http://${toolchain.params.ip}:8282/hudson/job/${Hudson.getJobName()}/${Hudson.getBuildNumber()}/consoleText`;
    if (appendLogURL) {
        elements.push({
            "tag": "markdown",
            "content": `[点击查看构建日志](${link})`,
            "text_align": "left",
            "text_size": "normal"
        });
    }

    if (versionInfo?.qrcodeFile) {
        elements.push(
            {
                "tag": "img",
                "img_key": versionInfo.qrcodeFile,
                "preview": true,
                "transparent": false,
                "scale_type": "crop_center",
                "size": "large",
                "alt": {
                    "tag": "plain_text",
                    "content": ""
                }
            }
        );
    }
    const supportRebuild = await Hudson.isSupportRebuild();
    if (supportRebuild) {
        elements.push({
            "tag": "action",
            "actions": [
                {
                    "tag": "button",
                    "text": {
                        "tag": "plain_text",
                        "content": "再构一次"
                    },
                    "type": "primary_filled",
                    "width": "default",
                    "size": "medium",
                    "icon": {
                        "tag": "standard_icon",
                        "token": "setting_outlined"
                    },
                    "confirm": {
                        "title": {
                            "tag": "plain_text",
                            "content": "重新构建"
                        },
                        "text": {
                            "tag": "plain_text",
                            "content": "是否确认再构一次？"
                        }
                    },
                    "behaviors": [
                        {
                            "type": "callback",
                            "value": "rebuild"
                        }
                    ]
                }
            ]
        });
    }
    return {
        "config": {
            "update_multi": true
        },
        "card_link": {
            "url": link
        },
        "i18n_elements": {
            "zh_cn": elements
        },
        "i18n_header": {
            "zh_cn": {
                "title": {
                    "tag": "plain_text",
                    "content": success ? "☀️版本构建成功" : "🌧️版本构建失败"
                },
                "subtitle": {
                    "tag": "plain_text",
                    "content": `@${toolchain.startUser}`
                },
                "template": success ? "green" : "red"
            }
        }
    };
}

function makeUserReport(success: boolean, versionInfo: TVersionInfo | null, additionalMsg: string, appendLogURL: boolean): feishu.ICardMessagePayload {
    const jobDesc = `${Hudson.getJobName()} #${Hudson.getBuildNumber()}`;
    let content: string;
    if (success) {
        content = `<font color='green'>你发起的版本构建已完成：${jobDesc}</font>`;
        if (versionInfo) {
            content += `\n版本号: ${versionInfo.version}`;
        } 
    } else {
        content = `<font color='red'>你发起的版本构建失败了：${jobDesc}</font>`;
    }
    if (additionalMsg) {
        content += `\n${additionalMsg}`;
    }
    const elements: feishu.IMsgElement[] = [
        {
            "tag": "markdown",
            content,
            "text_align": "left",
            "text_size": "normal",
            "icon": {
                "tag": "standard_icon",
                "token": "link-copy_outlined",
                "color": "blue"
            }
        }
    ];

    const link = `http://${toolchain.params.ip}:8282/hudson/job/${Hudson.getJobName()}/${Hudson.getBuildNumber()}/consoleText`;
    if (appendLogURL) {
        elements.push({
            "tag": "markdown",
            "content": `[点击查看构建日志](${link})`,
            "text_align": "left",
            "text_size": "normal"
        });
    }
    return {
        "config": {
            "update_multi": true
        },
        "card_link": {
            "url": ""
        },
        "i18n_elements": {
            "zh_cn": elements
        },
        "i18n_header": {}
    }
}

export async function sendBuildFailureAlert(msg: string, printMsg: boolean = true, suggestRetry = false): Promise<void> {
    if (printMsg) console.error(msg);

    if (msg.length > 512) {
        msg = msg.substring(0, 512) + `\n...more`;
    }
    
    const chatid = getChatId();
    if (chatid) {
        let content = msg;
        if (__alertVar.userAlreadyAlert) {
            content += `\n已通知 @${__alertVar.userAlreadyAlert} 进行处理`;
        }
        const report = await makeBuildReport(false, null, content, true);        
        // 先群发消息
        await sendRobotMsgInternal({
            chatid,
            payload: {
                msg_type: 'interactive',
                content: report
            }
        });
        if (suggestRetry) await sendRobotMsg('text', '别紧张，再构一次看看~', undefined, chatid);
    } else {
        console.log('group chat skipped cause no chatid');
    }

    if (!toolchain.startByTimer && toolchain.startUser) {
        if (__alertVar.userAlreadyAlert.toLowerCase() != toolchain.startUser.toLowerCase()) {
            // 再私发
            if (suggestRetry) msg += '\n请重新构建';
            const privateRpt = makeUserReport(false, null, msg, true);
            await sendRobotMsgInternal({
                ename: toolchain.startUser,
                payload: {
                    msg_type: 'interactive',
                    content: privateRpt
                }
            });
        }
    } else {
        console.log('user chat skipped cause cannot tell authenticated user.');
    }
}

export async function sendBuildSuccess(versionInfo: TVersionInfo | null, conclusion: string): Promise<void> {
    let msg = '';
    if (conclusion) msg = conclusion;

    const otherMsgs = toolchain.buildMessages.join('\n');
    if (otherMsgs) {
        if (msg) msg += '\n';
        msg += otherMsgs;
    }
    const chatid = getChatId();
    if (chatid) {
        const report = await makeBuildReport(true, versionInfo, msg, toolchain.appendLogURL);    
        // 先群发消息
        await sendRobotMsgInternal({
            chatid,
            payload: {
                msg_type: 'interactive',
                content: report
            }
        });
    } else {
        console.log('group chat skipped cause no chatid');
    }

    if (!toolchain.startByTimer && toolchain.startUser) {
        // 再私发
        const privateRpt = makeUserReport(true, versionInfo, msg, toolchain.appendLogURL);
        await sendRobotMsgInternal({
            ename: toolchain.startUser,
            payload: {
                msg_type: 'interactive',
                content: privateRpt
            }
        });
    } else {
        console.log('user chat skipped cause cannot tell authenticated user.');
    }
}

async function sendUserChat(type: 'text' | 'markdown' | 'image', touser: string, content: string): Promise<void> {
    const payload = makeRobotMsgPayload(type, content);
    if (!payload) {
        return;
    }
    const result = await sendRobotMsgInternal({ ename: touser, payload });
    if (result.code == 0) {
        __alertVar.userAlreadyAlert = touser;
    }
}

export async function sendRobotImage(base64: string, chatid?: string): Promise<feishu.IBaseResponse> {
    if (!chatid) {
        chatid = getChatId();
    }
    if (!chatid) {
        return { code: -1, msg: 'robot msg skipped cause no chatid.' };
    }
    const mch = base64.match(/^data:image\/(\w+);base64,/);
    if (mch == null) {
        console.log('base64 format error!');
        return { code: -1, msg: 'base64 format error!' };
    }
    const ext = mch[1];
    const base64Data = base64.replace(mch[0], '');
    const buffer = Buffer.from(base64Data, 'base64');
    const file = path.join(os.tmpdir(), `robotImage.${moment.now()}.${ext}`);
    await fs.writeFile(file, buffer);
    let payload: feishu.IRobotMsgPost = {
        chatid,
        payload: {
            msg_type: 'image',
            content: {
                image_key: file
            }
        }
    }
    return await sendRobotMsgInternal(payload);
}

export async function sendRobotMsg(type: 'text' | 'markdown' | 'file' | 'image', msg: string, mention?: string, chatid?: string, replyTo?: string): Promise<feishu.IBaseResponse> {
    if (!chatid) {
        chatid = getChatId();
    }
    if (!chatid) {
        return { code: -1, msg: 'robot msg skipped cause no chatid.' };
    }
    const payload = makeRobotMsgPayload(type, msg);
    if (!payload) {
        return { code: -1, msg: 'msg type not supported!' };
    }
    return await sendRobotMsgInternal({ chatid, payload, mention: mention ? [mention] : undefined, reply_id: replyTo });
}

function makeRobotMsgPayload(type: 'text' | 'markdown' | 'file' | 'image', msg: string): feishu.IMsgPayload | null {
    if (type == 'text') {
        return {
            msg_type: 'text',
            content: JSON.stringify({ text: msg })
        }
    }
    if (type == 'markdown') {
        // markdown格式将转为飞书卡片
        return {
            msg_type: 'interactive',
            content: {
                "config": {
                    "update_multi": true
                },
                "card_link": {
                    "url": ""
                },
                "i18n_elements": {
                    "zh_cn": [
                        {
                            "tag": "markdown",
                            "content": msg,
                            "text_align": "left",
                            "text_size": "normal"
                        }
                    ]
                },
                "i18n_header": {}
            }
        }
    }
    if (type == 'file') {
        return {
            msg_type: 'file',
            content: {
                file_key: msg
            }
        }
    }
    if (type == 'image') {
        return {
            msg_type: 'image',
            content: {
                image_key: msg
            }
        }
    }
    console.error('msg type not supported!');
    return null;
}

export async function sendRobotMsgInternal(payload: feishu.IRobotMsgPost): Promise<feishu.IBaseResponse> {
    const url = apiUrl('api/app/robotmsg');
    const result = await axios.post<feishu.IBaseResponse>(url, { data: payload }, { timeout: 3000, proxy: false }).catch((e) => {
        console.error('Exception when post robot msg:', url, e instanceof Error ? e.stack : e.toString());
        let msg: string;
        if (e instanceof Error) {
           msg = e.message;
           const d = (e as AxiosError<feishu.IBaseResponse>).response?.data;
           if (d) {
               msg += `, data: ${JSON.stringify(d)}`;
           }
        } else {
            msg = e.toString();
        }
        console.error(msg);
        return { data: { code: -1, msg }}
    });
    if (result.data.code != 0) {
        console.error(`robot msg sent failed: ${result.data.msg}, payload:`, payload);
    }
    // console.log('robot msg sent success:', payload, result);
    return result.data;
}

function apiUrl(url: string): string {
    let o = env.ChatSvr;
    if (!o.endsWith('/')) {
        o += '/';
    }
    return o + (url.startsWith('/') ? url.substring(1) : url);
}

export function emphasize(str: string): string {
    return `<font color='red'>**${str}**</font>`;
}